using System;
using System.Xml;
using System.Reflection;
using System.Configuration;

namespace bOS.XML
{
	/// <summary>
	/// Legge un file di configurazione in formato XML.
	/// </summary>
	/// <example>
	///	<code>
	///	config = new AnyConfig();
	/// //set the document path\name
	/// config.cfgFile = "app.config";
	/// //retrieve and output document values
	/// textBox1.Text = "Sample output from "+ config.cfgFile+":\r\n";
	/// textBox1.Text+= config.GetValue("//appSettings//add[@key='one']");

	/// // retrieve and output another document values
	/// config.cfgFile = "..\\..\\my.config";
	/// textBox1.Text += "\r\n\r\nNow output from "+ 
	/// config.cfgFile+" and DataGrid:\r\n";
	/// DateTime date =    (DateTime)( config.GetValue(
	/// "//allSettings//mySettings//set[@key='date']", 
	/// typeof( DateTime )) );
	/// date = date.AddMonths( 1 );
	/// textBox1.Text+= date.ToShortDateString()+"\r\n";
	/// textBox1.Text+= config.GetValue(
	/// "//allSettings//mySettings//set[@key='greeting']")+
	/// " "+( config.GetValue(
	/// "//allSettings//mySettings//set[@key='salutation']") )+"\r\n";
	/// textBox1.Text+= (bool)( config.GetValue( 
	/// "//allSettings//mySettings//set[@key='switch']",
	/// typeof( bool )) ) +"\r\n";
	/// 
	/// // remove a key/value pair
	/// config.removeElement("//allSettings//mySettings//set[@key='makes']");
	/// // add it back
	/// config.SetValue("//allSettings//mySettings//set[@key='makes']", 
	/// "more sense" );

	/// // retrieve and output values from another set of keys
	/// textBox1.Text+= config.GetValue(
	/// "//allSettings//yourSettings//your[@key='greeting']")+
	/// " "+( config.GetValue(
	/// "//allSettings//yourSettings//your[@key='salutation']") )+"\r\n";

	/// // display document
	/// ds = new DataSet();
	/// ds.ReadXml(config.cfgFile);
	/// //        dataGrid1.SetDataBinding(ds, "appSettings");
	/// dataGrid1.DataSource = ds.Tables["allSettings"];
	/// dataGrid1.Expand(-1);
	///	</code>
	/// </example>
	public class XMLConfigurationFile : System.Configuration.AppSettingsReader
	{
		private XmlNode node;
		private string _cfgFile;

		public   string cfgFile
		{
			get    { return _cfgFile; }
			set    { _cfgFile=value; }
		}

		public string GetValue (string key)
		{
			return Convert.ToString(GetValue(key, typeof(string)));
		}

		public new object GetValue (string key, System.Type sType)
		{
			XmlDocument doc = new XmlDocument();
			object ro = String.Empty;
			loadDoc(doc);
			string sNode = key.Substring(0, key.LastIndexOf("//"));
			// retrieve the selected node
			try
			{
				node =  doc.SelectSingleNode(sNode);
				if( node != null )
				{
					// Xpath selects element that contains the key
					XmlElement targetElem= (XmlElement)node.SelectSingleNode(
						key.Replace(sNode,"")) ;
					if (targetElem!=null)
					{
						ro = targetElem.GetAttribute("value");
					}
				}
				if (sType == typeof(string))
					return Convert.ToString(ro);
				else
					if (sType == typeof(bool))
				{
					if (ro.Equals("True") || ro.Equals("False"))
						return Convert.ToBoolean(ro);
					else
						return false;
				}
				else
					if (sType == typeof(int))
					return Convert.ToInt32(ro);
				else
					if (sType == typeof(double))
					return Convert.ToDouble(ro);
				else
					if (sType == typeof(DateTime))
					return Convert.ToDateTime(ro);
				else
					return Convert.ToString(ro);
			}
			catch
			{
				return String.Empty;
			}
		}

		public bool SetValue (string key, string val)
		{
			XmlDocument doc = new XmlDocument();
			loadDoc(doc);
			try
			{
				// retrieve the target node
				string sNode = key.Substring(0, key.LastIndexOf("//"));
				node =  doc.SelectSingleNode(sNode);
				if( node == null )
					return false;
				// Set element that contains the key
				XmlElement targetElem= (XmlElement) node.SelectSingleNode(
					key.Replace(sNode,""));
				if (targetElem!=null)
				{
					// set new value
					targetElem.SetAttribute("value", val);
				}
					// create new element with key/value pair and add it
				else
				{
					// handle xxx[@key='yyy']
					sNode = key.Substring(key.LastIndexOf("//")+2);
					// create new element xxx
					XmlElement entry = doc.CreateElement(sNode.Substring(0, 
						sNode.IndexOf("[@")).Trim());
					sNode =  sNode.Substring(sNode.IndexOf("'")+1);
					// set attribute key=yyy
					entry.SetAttribute("key", sNode.Substring(0, 
						sNode.IndexOf("'")) );
					// set attribute value=val
					entry.SetAttribute("value", val);
					node.AppendChild(entry);
				}
				saveDoc(doc, this._cfgFile);
				return true;
			}
			catch
			{
				return false;
			}
		}

		public bool removeElement (string key)
		{
			XmlDocument doc = new XmlDocument();
			loadDoc(doc);
			try
			{
				string sNode = key.Substring(0, key.LastIndexOf("//"));
				// retrieve the appSettings node
				node =  doc.SelectSingleNode("//appSettings");
				if( node == null )
					return false;
				// XPath select setting element that contains the key to remove
				node.RemoveChild( node.SelectSingleNode(key.Replace(sNode,"")) );
				saveDoc(doc, this._cfgFile);
				return true;
			}
			catch
			{
				return false;
			}
		}

		private void saveDoc (XmlDocument doc, string docPath)
		{
			// save document
			// choose to ignore if web.config since it may 
			// cause server sessions interruptions
			if(  this._cfgFile.Equals("web.config") )
				return;
			else
				try
				{
					XmlTextWriter writer = new XmlTextWriter( docPath , null );
					writer.Formatting = Formatting.Indented;
					doc.WriteTo( writer );
					writer.Flush();
					writer.Close();
					return;
				}
				catch
				{}
		}

		private void loadDoc ( XmlDocument doc )
		{
			// check for type of config file being requested
			if(  ( this._cfgFile == null) || (this._cfgFile.Equals("app.config") ) )
			{
				// use default app.config
				this._cfgFile = ((Assembly.GetEntryAssembly()).GetName()).Name+
					".exe.config";
			}
			else
				if(  this._cfgFile.Equals("web.config"))
			{
				// use server web.config
				//this._cfgFile = System.Web.HttpContext.Current.Server.MapPath(
				//	"web.config");
			}
			// load the document
			doc.Load( this._cfgFile );
		}

	}
}
